#include "config.h"
#include <string.h>

#include "xIPC.h"
#include "aux_types.h"
#include "aux_errno.h"
#include "aux_debugmsg.h"
#include "aux_queuemanager.h"
#include "aux_messagemanager.h"

#include "aux_thread.h"
EErrNo xIPC_Msg_DeepCopy(TMessage *ptNew, TMessage *ptOrg)
{
    if (!ptOrg || !ptNew)
        return -ERRNO_EPARAMETER_INVALID;

    memcpy(ptNew, ptOrg, sizeof(TMessage));

    if (ptOrg->nDataByteCnt > 0)
    {
        ptNew->pData = (void *) malloc(ptOrg->nDataByteCnt);
        if (NULL == ptNew->pData)
            return ERRNO_FAIL;
        memcpy(ptNew->pData, ptOrg->pData, ptOrg->nDataByteCnt);
    }

    return ERRNO_SUCCESS;
}

/* call the listener of router to process the message */
static EErrNo s_xIPC_Msg_ListenerHasMsg(void *pListenrData,
                                                    u32 nSize, void *pParameter)
{
    TMessageListener *ptListenerInQueue = (TMessageListener *)pListenrData;
    TMessage         *ptMessage         = (TMessage *)pParameter;

    if ((!ptListenerInQueue) || (!ptMessage) ||
        !(ptListenerInQueue->pMessageHandler))
        return -ERRNO_EPARAMETER_INVALID;

    if (ptListenerInQueue->eListenFilterType & LISTEN_TYPE_ID)
    {
        if (ptListenerInQueue->nSenderId != ptMessage->nIdSender)
            goto NOTHING_TO_DO;
    }

    if (ptListenerInQueue->eListenFilterType & LISTEN_TYPE_NAME)
    {
        if (strcmp(ptListenerInQueue->szSender, ptMessage->szSender))
            goto NOTHING_TO_DO;
    }

    if (ptListenerInQueue->eListenFilterType & LISTEN_TYPE_MSG)
    {
        if (ptListenerInQueue->eMsgId != ptMessage->eMessageId)
            goto NOTHING_TO_DO;
    }

    if (ptListenerInQueue->eListenFilterType & LISTEN_TYPE_NOT_ID)
    {
        if (ptListenerInQueue->nSenderId == ptMessage->nIdSender)
            goto NOTHING_TO_DO;
    }

    if (ptListenerInQueue->eListenFilterType & LISTEN_TYPE_NOT_NAME)
    {
        if (!strcmp(ptListenerInQueue->szSender, ptMessage->szSender))
            goto NOTHING_TO_DO;
    }

    if (ptListenerInQueue->eListenFilterType & LISTEN_TYPE_NOT_MSG)
    {
        if (ptListenerInQueue->eMsgId == ptMessage->eMessageId)
            goto NOTHING_TO_DO;
    }

    return (ptListenerInQueue->pMessageHandler)(ptListenerInQueue, ptMessage);

NOTHING_TO_DO:
    return -ERRNO_EWRONG;
}

static EErrNo s_MessageManager_FindListenerWantedInQueue(
                            void *pListenrData, u32 nSize, void *pParameter)
{
    TMessageListener *ptListenerInQueue = (TMessageListener *)pListenrData;
    TMessageListener *ptListenerWanted  = (TMessageListener *)pParameter;

    if (ptListenerInQueue && ptListenerWanted &&
        ptListenerInQueue->nListenerId == ptListenerWanted->nListenerId)
        return ERRNO_TRUE;
    else
        return ERRNO_FALSE;
}

EErrNo xIPC_Msg_TraverseListener(TMessageManager *ptManager,
                                                       TMessage *ptMessage)
{
    EErrNo eRet = ERRNO_SUCCESS;

    if (!ptManager || !ptMessage)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS != xIPCQueueTraverse(&(ptManager->tQueueListener),
                                           s_xIPC_Msg_ListenerHasMsg,
                                           ptMessage))
        return ERRNO_FAIL;

    return eRet;
}

/* xIPC_Msg_AddMessage add the message, just malloc, and copy, it means
   grab the data pointer */
EErrNo xIPC_Msg_AddMessage(TMessageManager *ptManager,
                                            TMessage        *ptMessage)
{
#define __FUNCTION_NAME__ "xIPC_Msg_AddMessage"

    EErrNo eRet = ERRNO_SUCCESS;

    if (!ptManager || !ptMessage)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    aux_prt_debug("add to queue %p\n", &(ptManager->tQueueMessage));
    if (ERRNO_SUCCESS != xIPCQueuePushBack(&(ptManager->tQueueMessage),
                                            ptMessage, sizeof(TMessage)))
    {
        AUX_ERR_STR("add to queue fail\n");
        return -ERRNO_EADDMSGFAIL;
    }
    if (ERRNO_VALID ==
            xIPCChkPthreadMutexValid(&(ptManager->tQueueMessageIncreaseMutex)) &&
        pthread_mutex_lock(&(ptManager->tQueueMessageIncreaseMutex)))
    {
        AUX_ERR_STR("lock fail\n");
        return -ERRNO_ELOCK_FAIL;
    }

    if (pthread_cond_signal(&(ptManager->tQueueMessageIncreaseCond)))
    {
        AUX_ERR_STR("signal cond fail, ignore\n");
        eRet = -ERRNO_ECOND_WAIT_FAIL;
    }

    if (pthread_mutex_unlock(&(ptManager->tQueueMessageIncreaseMutex)))
    {
        AUX_ERR_STR("unlock fail, ignore\n");
        eRet = -ERRNO_EUNLOCK_FAIL;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPC_Msg_PickMsg(TMessageManager *ptManager,
                                                TMessage **pptMessage)
{
#define __FUNCTION_NAME__ "xIPC_Msg_PickMsg"

    if (!ptManager || !pptMessage)
        return -ERRNO_EPARAMETER_INVALID;

    aux_prt_debug("try to pick from queue %p\n", &(ptManager->tQueueMessage));
    if (ERRNO_SUCCESS != xIPCQueuePopHead(&(ptManager->tQueueMessage),
                                           (void **)pptMessage, (u32 *)NULL))
    {
        AUX_ERR_STR("xIPCQueuePopHead fail\n");
        return ERRNO_FAIL;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPC_Msg_WaitForMsg(TMessageManager *ptManager)
{
    u32    nCnt = 0;
    EErrNo eRet = ERRNO_SUCCESS;

    if (!ptManager)
    {
        return -ERRNO_EPARAMETER_INVALID;
    }

    /* in order to speed up the program, get the count first */
    if (ERRNO_SUCCESS ==
            xIPCQueueNodeCnt(&(ptManager->tQueueMessage), &nCnt) && (nCnt > 0))
    {
        /*
         * may become empty now,
         * the upper will get fail,
         * but it doesn't matter
         */
        return ERRNO_SUCCESS;
    }

    if (ERRNO_INVALID ==
            xIPCChkPthreadMutexValid(&(ptManager->tQueueMessageIncreaseMutex)))
        return -ERRNO_EINVALID_MUTEX;

    if (pthread_mutex_lock(&(ptManager->tQueueMessageIncreaseMutex)))
        return -ERRNO_ELOCK_FAIL;

    /* use the following for the case when lock, a node is added */
    if (ERRNO_SUCCESS ==
            xIPCQueueNodeCnt(&(ptManager->tQueueMessage), &nCnt) && nCnt > 0)
    {
        /*
         * will not become empty now
         */
        eRet = ERRNO_SUCCESS;
        goto EXIT_WITH_MUTEX_LOCK;
    }

    if (pthread_cond_wait(&(ptManager->tQueueMessageIncreaseCond),
                           &(ptManager->tQueueMessageIncreaseMutex)))
        eRet = -ERRNO_ECOND_WAIT_FAIL;

EXIT_WITH_MUTEX_LOCK:
    if (pthread_mutex_unlock(&(ptManager->tQueueMessageIncreaseMutex)))
        eRet = -ERRNO_EUNLOCK_FAIL;

    return eRet;
}

EErrNo xIPC_Msg_GetMsgCnt(TMessageManager *ptManager,
                                              u32             *pnCnt)
{
    u32    nCnt = 0;
    EErrNo eRet = ERRNO_SUCCESS;

    if (!ptManager || !pnCnt)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS == xIPCQueueNodeCnt(&(ptManager->tQueueMessage), pnCnt))
        return ERRNO_SUCCESS;
    else
        return ERRNO_FAIL;
}


EErrNo xIPC_Msg_WaitForMsgTimeout(TMessageManager *ptManager,
                                                     u32              nMs)
{
#define __FUNCTION_NAME__ "xIPC_Msg_WaitForMsgTimeout"
    u32             nCnt    = 0;
    EErrNo          eRet    = ERRNO_SUCCESS;
    struct timespec tTime;
    u64             llTime;

    if (!ptManager)
        return -ERRNO_EPARAMETER_INVALID;

    /* in order to speed up the program, get the count first */
    if (ERRNO_SUCCESS ==
            xIPCQueueNodeCnt(&(ptManager->tQueueMessage), &nCnt) && (nCnt > 0))
    {
        /*
         * may become empty now,
         * the upper will get fail,
         * but it doesn't matter
         */
        return ERRNO_SUCCESS;
    }

    if (ERRNO_SUCCESS != aux_get_timestamp_ms(&llTime))
    {
        AUX_DEBUG_STR("get time fail\n");
        return ERRNO_FAIL;
    }

    if (ERRNO_INVALID ==
            xIPCChkPthreadMutexValid(&(ptManager->tQueueMessageIncreaseMutex)))
        return -ERRNO_EINVALID_MUTEX;

    tTime.tv_sec  = nMs / 1000 + llTime / 1000;
    tTime.tv_nsec = (nMs % 1000) * 1000 + (llTime % 1000) * 1000;
    if (pthread_mutex_lock(&(ptManager->tQueueMessageIncreaseMutex)))
        return -ERRNO_ELOCK_FAIL;

    /* use the following for the case when lock, a node is added */
    if (ERRNO_SUCCESS ==
            xIPCQueueNodeCnt(&(ptManager->tQueueMessage), &nCnt) && nCnt > 0)
    {
        /*
         * will not become empty now
         */
        eRet = ERRNO_SUCCESS;
        goto EXIT_WITH_MUTEX_LOCK;
    }

    eRet = pthread_cond_timedwait(&(ptManager->tQueueMessageIncreaseCond),
                                  &(ptManager->tQueueMessageIncreaseMutex),
                                  &tTime);

EXIT_WITH_MUTEX_LOCK:
    if (pthread_mutex_unlock(&(ptManager->tQueueMessageIncreaseMutex)))
        eRet = -ERRNO_EUNLOCK_FAIL;

    if (0 == eRet)
        return ERRNO_SUCCESS;
    else if (-ETIMEDOUT == eRet)
        return ERRNO_TIMEOUT;
    else
        return -ERRNO_EWRONG;
#undef __FUNCTION_NAME__
}

/* note: This function will grab the buffer pointer, so MUST created by malloc */
EErrNo xIPC_Msg_AddListener(TMessageManager  *ptManager,
                                                TMessageListener *ptData)
{
    if (!ptManager || !ptData)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS != xIPCQueuePushBack(&(ptManager->tQueueListener), ptData,
                                            sizeof(TMessageListener)))
        return ERRNO_FAIL;

    return ERRNO_SUCCESS;
}

/* pick off a listener from the queue */
EErrNo xIPC_Msg_PickListener(TMessageManager *ptManager,
                                               TMessageListener **pptData)
{
    if (!ptManager || !pptData)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS != xIPCQueuePopHead(&(ptManager->tQueueListener),
                                          (void **)pptData, (u32 *)NULL))
        return ERRNO_FAIL;

    return ERRNO_SUCCESS;
}

/*
 * WARNING:may cause free and referrence conflict.
 * only get data, not pick off from the queue
 */
EErrNo xIPC_Msg_GetListener(TMessageManager *ptManager,
                                                  TMessageListener **pptData)
{
    if (!ptManager || !pptData)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS != xIPCQueueGetHead(&(ptManager->tQueueListener),
                                           (void **)pptData, (u32 *)NULL))
        return ERRNO_FAIL;

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Msg_DeleteListener(
                     TMessageManager *ptManager, TMessageListener *pListenrData)
{
#define __FUNCTION_NAME__ "xIPC_Msg_DeleteListener"

    EErrNo eRet =
        xIPCQueueDeleteFirstIfCbReturnTrue(
                                     &(ptManager->tQueueListener),
                                     s_MessageManager_FindListenerWantedInQueue,
                                     pListenrData);

    if (eRet != ERRNO_SUCCESS && eRet != ERRNO_NOTFIND)
    {
        AUX_ERR_STR("delete listener fail\n");
        return ERRNO_FAIL;
    }

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

/* Will be called when destroy the queue */
static EErrNo s_xIPCDestroyListenerInQueue(void *pListenerData, u32 nSize)
{
    TMessageListener *ptListener = (TMessageListener *)pListenerData;

    if (ptListener)
    {
        if (ptListener->pListenerData)
        {
            free(ptListener->pListenerData);
            ptListener->pListenerData = NULL;
        }

        free(ptListener);
        ptListener = NULL;
    }

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Msg_DeleteAllListener(
                     TMessageManager *ptManager)
{
#define __FUNCTION_NAME__ "xIPC_Msg_DeleteAllListener"

    EErrNo eRet = xIPCQueueClear(&(ptManager->tQueueListener),
                                 s_xIPCDestroyListenerInQueue);
    if (eRet != ERRNO_SUCCESS)
    {
        AUX_ERR_STR("clear listener queue fail\n");
        return ERRNO_FAIL;
    }
    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

/* Will be called when destroy the queue */
static EErrNo s_xIPCDestroyMessageInQueue(void *ptMessageData, u32 nSize)
{
    TMessage *ptMsg = (TMessage *)ptMessageData;

    if (ptMsg)
    {
        if (ptMsg->pData)
            free(ptMsg->pData);

        free(ptMsg);
    }

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Msg_Manager_Init(TMessageManager *ptManager,
                                     const char *pszMsgQueueName,
                                     const char *pszListenerQueueName)
{
#define __FUNCTION_NAME__ "xIPC_Msg_Manager_Init"

    if (!ptManager || !pszMsgQueueName || !pszListenerQueueName)
    {
        AUX_ERR_STR("parameter error\n");
        return -ERRNO_EPARAMETER_INVALID;
    }

    memset(ptManager, 0, sizeof(TMessageManager));
    if (pthread_mutex_init(&(ptManager->tQueueMessageIncreaseMutex), NULL))
    {
        AUX_ERR_STR("init mutex fail\n");
        return ERRNO_FAIL;
    }

    if (pthread_cond_init(&(ptManager->tQueueMessageIncreaseCond), NULL))
    {
        AUX_ERR_STR("init cond fail\n");
        return ERRNO_FAIL;
    }

    if (ERRNO_SUCCESS != xIPCQueueInit(&(ptManager->tQueueMessage),
                                        pszMsgQueueName,
                                        s_xIPCDestroyMessageInQueue))
    {
        AUX_ERR_STR("init message queue fail\n");
        return ERRNO_FAIL;
    }

    if (ERRNO_SUCCESS != xIPCQueueInit(&(ptManager->tQueueListener),
                                        pszListenerQueueName,
                                        s_xIPCDestroyListenerInQueue))
    {
        AUX_ERR_STR("init listener queue fail\n");
        return ERRNO_FAIL;
    }

    return ERRNO_SUCCESS;

#undef __FUNCTION_NAME__
}

EErrNo xIPC_Msg_Deinit(TMessageManager *ptManager)
{
#define __FUNCTION_NAME__ "xIPC_Msg_Deinit"

    if (!ptManager)
        return -ERRNO_EPARAMETER_INVALID;

    /* even the mutex and cond deinit fail, just ignore it */
    if (pthread_cond_destroy(&(ptManager->tQueueMessageIncreaseCond)))
    {
        AUX_DEBUG_STR("deinit cond fail, ignore\n");
    }

    if (pthread_mutex_destroy(&(ptManager->tQueueMessageIncreaseMutex)))
    {
        AUX_DEBUG_STR("deinit mutex fail, ignore\n");
    }

    if (ERRNO_SUCCESS != xIPCQueueDeinit(&(ptManager->tQueueMessage), NULL))
    {
        AUX_DEBUG_STR("deinit message queue fail, ignore\n");
    }

    if (ERRNO_SUCCESS != xIPCQueueDeinit(&(ptManager->tQueueListener), NULL))
    {
        AUX_DEBUG_STR("deinit listener queue fail, ignore\n");
    }

    memset(ptManager, 0, sizeof(TMessageManager));

    return ERRNO_SUCCESS;

#undef __FUNCTION_NAME__
}

EErrNo xIPC_Msg_GetFlattenSize(TMessage *ptMsg, u32 *pnSize)
{
    if (!ptMsg || !pnSize || (ptMsg->nDataByteCnt > 0 && NULL == ptMsg->pData))
        return -ERRNO_EPARAMETER_INVALID;

    *pnSize = 0
    /* typedef struct {                                                       */
    /*     ExIPCMessageId          eMessageId;                                */
        + sizeof(u32)
    /*     EMessageSourceType      eMessageSourceType;                        */
        + sizeof(u32)
    /*     EMessageDestinationType eMessageDestinationType;                   */
        + sizeof(u32)
    /*     u64                     llTimeMsWhenSend;                          */
        + sizeof(u64)
    /*     u32                 anMessageData[MESSAGE_DWORD_DATA_MAX_LENGTH];  */
        + sizeof(u32) * MESSAGE_DWORD_DATA_MAX_LENGTH
    /*     u32                     nMessageDataDWordCnt;                      */
        + sizeof(u32)
    /*     u32                  nMessageContTotalCnt;                         */
        + sizeof(u32)
    /*     u32                  nMessageContNo;                               */
        + sizeof(u32)
    /*     u32                  nMessageCnt;                                  */
        + sizeof(u32)
    /*                                                                        */
    /*     u32                  nClientId;                                    */
        + sizeof(u32)
    /*     char                 szClient[TERMINAL_NAME_LENGTH];               */
        + sizeof(char) * TERMINAL_NAME_LENGTH
    /*                                                                        */
    /*     u32                  nIdSender;                                    */
        + sizeof(u32)
    /*     char                 szSender[TERMINAL_NAME_LENGTH];               */
        + sizeof(char) * TERMINAL_NAME_LENGTH
    /*     u32                  nIdReceiverFilter;                            */
        + sizeof(u32)
    /*     char                 szReceiverFilter[TERMINAL_NAME_LENGTH];       */
        + sizeof(char) * TERMINAL_NAME_LENGTH
    /*     EReceiverFilterType  eReceiverFilterType;                          */
        + sizeof(u32)
    /*                                                                        */
    /*     u32                  nDataByteCnt;                                 */
        + sizeof(u32)
    /*     void                *pData;                                        */
        + sizeof(u32) /* this place not used in flatten struct */
    /* } TMessage;                                                            */
        + ptMsg->nDataByteCnt;

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Msg_GetFlattenMiniSize(u32 *pnSize)
{
    TMessage tMsg;

    memset(&tMsg, 0, sizeof(TMessage));

    return xIPC_Msg_GetFlattenSize(&tMsg, pnSize);
}

EErrNo xIPC_Msg_GetDataMaxSize(u32 *pnSize)
{
    EErrNo   eRet;
    u32      nSize;

    if (!pnSize)
        return -ERRNO_EPARAMETER_INVALID;

    eRet = xIPC_Msg_GetFlattenMiniSize(&nSize);

    if (ERRNO_SUCCESS != eRet)
        return ERRNO_FAIL;

    *pnSize = CLIENT_SOCKET_RECV_BUFFER_BYTE_CNT - nSize;
    return ERRNO_SUCCESS;
}


EErrNo xIPC_Msg_Flatten(TMessage *ptMsg,
                                                    void *pBuffer, u32 *pnSize)
{
    u32 nSizeRequired = 0;
    u8  *pbyBuffer = (u8 *)pBuffer;

    if (!ptMsg || !pBuffer || !pnSize)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS !=
        xIPC_Msg_GetFlattenSize(ptMsg, &nSizeRequired))
        return ERRNO_FAIL;

    if (*pnSize < nSizeRequired)
        return -ERRNO_EMEMORY_NOT_SUFFICIENT;

    /* typedef struct {                                                       */
    /*     ExIPCMessageId          eMessageId;                                */
    *((u32 *)pbyBuffer) = ptMsg->eMessageId;
        pbyBuffer += sizeof(u32);
    /*     EMessageSourceType      eMessageSourceType;                        */
    *((u32 *)pbyBuffer) = ptMsg->eMessageSourceType;
    pbyBuffer += sizeof(u32);
    /*     EMessageDestinationType eMessageDestinationType;                   */
    *((u32 *)pbyBuffer) = ptMsg->eMessageDestinationType;
    pbyBuffer += sizeof(u32);
    /*     u64                     llTimeMsWhenSend;                          */
    *((u64 *)pbyBuffer) = ptMsg->llTimeMsWhenSend;
    pbyBuffer +=  sizeof(u64);
    /*     u32                 anMessageData[MESSAGE_DWORD_DATA_MAX_LENGTH];  */
    memcpy(pbyBuffer, ptMsg->anMessageData,
           sizeof(u32) * MESSAGE_DWORD_DATA_MAX_LENGTH);
    pbyBuffer += sizeof(u32) * MESSAGE_DWORD_DATA_MAX_LENGTH;
    /*     u32                     nMessageDataDWordCnt;                      */
    *((u32 *)pbyBuffer) = ptMsg->nMessageDataDWordCnt;
    pbyBuffer += sizeof(u32);
    /*     u32                  nMessageContTotalCnt;                         */
    *((u32 *)pbyBuffer) = ptMsg->nMessageContTotalCnt;
    pbyBuffer += sizeof(u32);
    /*     u32                  nMessageContNo;                               */
    *((u32 *)pbyBuffer) = ptMsg->nMessageContNo;
    pbyBuffer += sizeof(u32);
    /*     u32                  nMessageCnt;                                  */
    *((u32 *)pbyBuffer) = ptMsg->nMessageCnt;
    pbyBuffer += sizeof(u32);
    /*                                                                        */
    /*     u32                  nClientId;                                    */
    *((u32 *)pbyBuffer) = ptMsg->nClientId;
    pbyBuffer += sizeof(u32);
    /*     char                 szClient[TERMINAL_NAME_LENGTH];               */
    memcpy(pbyBuffer, ptMsg->szClient,
           sizeof(char) * TERMINAL_NAME_LENGTH);
    pbyBuffer +=  sizeof(char) * TERMINAL_NAME_LENGTH;
    /*                                                                        */
    /*     u32                  nIdSender;                                    */
    *((u32 *)pbyBuffer) = ptMsg->nIdSender;
    pbyBuffer += sizeof(u32);
    /*     char                 szSender[TERMINAL_NAME_LENGTH];               */
    memcpy(pbyBuffer, ptMsg->szSender,
           sizeof(char) * TERMINAL_NAME_LENGTH);
    pbyBuffer +=  sizeof(char) * TERMINAL_NAME_LENGTH;
    /*     u32                  nIdReceiverFilter;                            */
    *((u32 *)pbyBuffer) = ptMsg->nIdReceiverFilter;
    pbyBuffer += sizeof(u32);
    /*     char                 szReceiverFilter[TERMINAL_NAME_LENGTH];       */
    memcpy(pbyBuffer, ptMsg->szReceiverFilter,
           sizeof(char) * TERMINAL_NAME_LENGTH);
    pbyBuffer +=  sizeof(char) * TERMINAL_NAME_LENGTH;
    /*     EReceiverFilterType  eReceiverFilterType;                          */
    *((u32 *)pbyBuffer) = ptMsg->eReceiverFilterType;
    pbyBuffer += sizeof(u32);
    /*                                                                        */
    /*     u32                  nDataByteCnt;                                 */
    *((u32 *)pbyBuffer) = ptMsg->nDataByteCnt;
    pbyBuffer += sizeof(u32);
    /*     void                *pData;                                        */
    pbyBuffer += sizeof(u32); /* this place not used in flatten struct */
    /* } TMessage;                                                            */
    if (ptMsg->pData && ptMsg->nDataByteCnt > 0)
        memcpy(pbyBuffer, ptMsg->pData, ptMsg->nDataByteCnt);

    return ERRNO_SUCCESS;

}

EErrNo xIPC_Msg_GetDataSizeFromFlatten(void *pBuffer,
                                                                u32 *pnSize)
{
    u32 nOffsetOfDataSize = 0;
    u8 *pbyBuffer         = (u8 *)pBuffer;

    if (!pBuffer || !pnSize)
        return -ERRNO_EPARAMETER_INVALID;

    nOffsetOfDataSize = 0
    /* typedef struct {                                                       */
    /*     ExIPCMessageId          eMessageId;                                */
        + sizeof(u32)
    /*     EMessageSourceType      eMessageSourceType;                        */
        + sizeof(u32)
    /*     EMessageDestinationType eMessageDestinationType;                   */
        + sizeof(u32)
    /*     u64                     llTimeMsWhenSend;                          */
        + sizeof(u64)
    /*     u32                 anMessageData[MESSAGE_DWORD_DATA_MAX_LENGTH];  */
        + sizeof(u32) * MESSAGE_DWORD_DATA_MAX_LENGTH
    /*     u32                     nMessageDataDWordCnt;                      */
        + sizeof(u32)
    /*     u32                  nMessageContTotalCnt;                         */
        + sizeof(u32)
    /*     u32                  nMessageContNo;                               */
        + sizeof(u32)
    /*     u32                  nMessageCnt;                                  */
        + sizeof(u32)
    /*                                                                        */
    /*     u32                  nClientId;                                    */
        + sizeof(u32)
    /*     char                 szClient[TERMINAL_NAME_LENGTH];               */
        + sizeof(char) * TERMINAL_NAME_LENGTH
    /*                                                                        */
    /*     u32                  nIdSender;                                    */
        + sizeof(u32)
    /*     char                 szSender[TERMINAL_NAME_LENGTH];               */
        + sizeof(char) * TERMINAL_NAME_LENGTH
    /*     u32                  nIdReceiverFilter;                            */
        + sizeof(u32)
    /*     char                 szReceiverFilter[TERMINAL_NAME_LENGTH];       */
        + sizeof(char) * TERMINAL_NAME_LENGTH
    /*     EReceiverFilterType  eReceiverFilterType;                          */
        + sizeof(u32);

    pbyBuffer += nOffsetOfDataSize;

    *pnSize = *((u32 *)pbyBuffer);

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Msg_GetMsgTypeFromFlatten(void *pBuffer,
                                                         ExIPCMessageId *peType)
{
    u32 nOffsetOfDataSize = 0;
    u8 *pbyBuffer         = (u8 *)pBuffer;

    if (!pBuffer || !peType)
        return -ERRNO_EPARAMETER_INVALID;

    nOffsetOfDataSize = 0
    /* typedef struct {                                                       */
    /*     ExIPCMessageId          eMessageId;                                */
                        ;

    pbyBuffer += nOffsetOfDataSize;

    *peType = (ExIPCMessageId)(*((u32 *)pbyBuffer));

    return ERRNO_SUCCESS;
}



/*
 * pDataBuffer can be NULL, pnSize can be NULL, but pnSize is not NULL and
 * pnSize > 0, then memory must valid
 */
EErrNo xIPC_Msg_Embody(TMessage *ptMsg,
                       void     *pDataBuffer,
                       u32      *pnSize,
                       void     *pFlattenBuffer)
{
#define __FUNCTION_NAME__ "xIPC_Msg_Embody"
    u32 nDataBufferSizeRequired = 0;
    u8 *pbyBuffer = (u8 *)pFlattenBuffer;
    u8  byBufferReady = 0;

    if (!ptMsg || !pFlattenBuffer)
        return -ERRNO_EPARAMETER_INVALID;

    if (pDataBuffer && ((*pnSize == 0) || !pnSize))
        return -ERRNO_EPARAMETER_INVALID;

    if (pnSize && (*pnSize > 0) && !pDataBuffer)
        return -ERRNO_EPARAMETER_INVALID;

    memset(ptMsg, 0, sizeof(TMessage));

    if (ERRNO_SUCCESS != xIPC_Msg_GetDataSizeFromFlatten(
                            pFlattenBuffer, &nDataBufferSizeRequired))
        return ERRNO_FAIL;

    if (pnSize && (*pnSize > 0) && nDataBufferSizeRequired > *pnSize)
    {
        aux_prt_err("memory not sufficient need %d > %d\n",
                    nDataBufferSizeRequired, *pnSize);
        return -ERRNO_EMEMORY_NOT_SUFFICIENT;
    }

    if (pnSize && (*pnSize > 0) && nDataBufferSizeRequired <= *pnSize)
        byBufferReady = 1;

    /* typedef struct {                                                       */
    /*     ExIPCMessageId          eMessageId;                                */
    ptMsg->eMessageId = (ExIPCMessageId)(*((u32 *)pbyBuffer));
    pbyBuffer += sizeof(u32);
    /*     EMessageSourceType      eMessageSourceType;                        */
    ptMsg->eMessageSourceType = (EMessageSourceType)(*((u32 *)pbyBuffer));
    pbyBuffer += sizeof(u32);
    /*     EMessageDestinationType eMessageDestinationType;                   */
    ptMsg->eMessageDestinationType = (EMessageDestinationType)(*((u32 *)pbyBuffer));
    pbyBuffer += sizeof(u32);
    /*     u64                     llTimeMsWhenSend;                          */
    ptMsg->llTimeMsWhenSend = *((u64 *)pbyBuffer);
    pbyBuffer +=  sizeof(u64);
    /*     u32                 anMessageData[MESSAGE_DWORD_DATA_MAX_LENGTH];  */
    memcpy(ptMsg->anMessageData, pbyBuffer,
           sizeof(u32) * MESSAGE_DWORD_DATA_MAX_LENGTH);
    pbyBuffer += sizeof(u32) * MESSAGE_DWORD_DATA_MAX_LENGTH;
    /*     u32                     nMessageDataDWordCnt;                      */
    ptMsg->nMessageDataDWordCnt = *((u32 *)pbyBuffer);
    pbyBuffer += sizeof(u32);
    /*     u32                  nMessageContTotalCnt;                         */
    ptMsg->nMessageContTotalCnt = *((u32 *)pbyBuffer);
    pbyBuffer += sizeof(u32);
    /*     u32                  nMessageContNo;                               */
    ptMsg->nMessageContNo = *((u32 *)pbyBuffer);
    pbyBuffer += sizeof(u32);
    /*     u32                  nMessageCnt;                                  */
    ptMsg->nMessageCnt = *((u32 *)pbyBuffer);
    pbyBuffer += sizeof(u32);
    /*                                                                        */
    /*     u32                  nClientId;                                    */
    ptMsg->nClientId = *((u32 *)pbyBuffer);
    pbyBuffer += sizeof(u32);
    /*     char                 szClient[TERMINAL_NAME_LENGTH];               */
    memcpy(ptMsg->szClient, pbyBuffer,
           sizeof(char) * TERMINAL_NAME_LENGTH);
    pbyBuffer +=  sizeof(char) * TERMINAL_NAME_LENGTH;
    /*                                                                        */
    /*     u32                  nIdSender;                                    */
    ptMsg->nIdSender = *((u32 *)pbyBuffer);
    pbyBuffer += sizeof(u32);
    /*     char                 szSender[TERMINAL_NAME_LENGTH];               */
    memcpy(ptMsg->szSender, pbyBuffer,
           sizeof(char) * TERMINAL_NAME_LENGTH);
    pbyBuffer +=  sizeof(char) * TERMINAL_NAME_LENGTH;
    /*     u32                  nIdReceiverFilter;                            */
    ptMsg->nIdReceiverFilter = *((u32 *)pbyBuffer);
    pbyBuffer += sizeof(u32);
    /*     char                 szReceiverFilter[TERMINAL_NAME_LENGTH];       */
    memcpy(ptMsg->szReceiverFilter, pbyBuffer,
           sizeof(char) * TERMINAL_NAME_LENGTH);
    pbyBuffer +=  sizeof(char) * TERMINAL_NAME_LENGTH;
    /*     EReceiverFilterType  eReceiverFilterType;                          */
    ptMsg->eReceiverFilterType = (EReceiverFilterType)(*((u32 *)pbyBuffer));
    pbyBuffer += sizeof(u32);
    /*                                                                        */
    /*     u32                  nDataByteCnt;                                 */
    if (byBufferReady)
        ptMsg->nDataByteCnt = *((u32 *)pbyBuffer);
    else
        ptMsg->nDataByteCnt = 0;
    pbyBuffer += sizeof(u32);
    /*     void                *pData;                                        */
    if (byBufferReady)
        ptMsg->pData = pDataBuffer;
    else
        ptMsg->pData = NULL;
    pbyBuffer += sizeof(u32); /* this place not used in flatten struct */
    /* } TMessage;                                                            */

    if (pnSize)
        *pnSize = nDataBufferSizeRequired;
    if (byBufferReady)
        memcpy(ptMsg->pData, pbyBuffer, ptMsg->nDataByteCnt);

    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPC_Msg_GetFlattenAuto(TMessage *ptMsg,
                               void **ppData, u32 *pnSize)
{
#define __FUNCTION_NAME__ "xIPC_Msg_GetFlattenAuto"
    u32 nFlattenSize = 0;
    void *pData;

    if (!ptMsg || !pnSize || !ppData)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS != xIPC_Msg_GetFlattenSize(ptMsg, &nFlattenSize))
    {
        AUX_ERR_STR("get flatten size fail\n");
        return ERRNO_FAIL;
    }

    if (0 == nFlattenSize)
    {
        AUX_ERR_STR("error, flatten size is 0\n");
        return ERRNO_FAIL;
    }

    pData = malloc(nFlattenSize);
    if (!pData)
    {
        AUX_DEBUG_STR_UINT_ENDL("malloc fail, size=", nFlattenSize);
        return -ERRNO_EMALLOC_FAIL;
    }

    if (ERRNO_SUCCESS != xIPC_Msg_Flatten(ptMsg, pData, &nFlattenSize))
    {
        free(pData);
        AUX_ERR_STR("flatten fail\n");
        return ERRNO_FAIL;
    }

    *ppData = pData;
    *pnSize = nFlattenSize;
    return ERRNO_SUCCESS;
#undef __FUNCTION_NAME__
}

EErrNo xIPC_Msg_PutFlattenAuto(void *pData, u32 nSize)
{
    if (pData)
        free(pData);

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Msg_GetEmbodyMsgAuto(TMessage *ptMsg,
                                 void  *pDataBuffer,
                                 u32    nDataByteCnt)
{
#define __FUNCTION_NAME__ "xIPC_Msg_GetEmbodyMsgAuto"
    u32 nDataSize = 0;
    void *pDataBuf = NULL;
    u32 nMiniSize;
    EErrNo eRet;

    if (ERRNO_SUCCESS !=
        xIPC_Msg_GetDataSizeFromFlatten(pDataBuffer, &nDataSize))
    {
        AUX_ERR_STR("get data size fail\n");
        return ERRNO_FAIL;
    }

    if (ERRNO_SUCCESS != xIPC_Msg_GetFlattenMiniSize(&nMiniSize))
    {
        AUX_ERR_STR("get mini size fail\n");
        return ERRNO_FAIL;
    }

    if (nMiniSize + nDataSize > nDataByteCnt) /* message is wrong */
    {
        AUX_ERR_STR("data size too small\n");
        return ERRNO_FAIL;
    }

    if (0 != nDataSize)
    {
        pDataBuf = (void *)malloc(nDataSize);
        if (!(pDataBuf))
        {
            AUX_ERR_STR("malloc fail\n");
            return ERRNO_FAIL;
        }
    }

    eRet = xIPC_Msg_Embody(ptMsg, pDataBuf, &nDataSize, pDataBuffer);
    if (ERRNO_SUCCESS != eRet)
    {
        aux_prt_err("embody fail %d\n", eRet);

        free(pDataBuf);
        pDataBuf = NULL;

        return ERRNO_FAIL;
    }

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Msg_PutEmbodyMsg(TMessage *ptMsg)
{
    u32 nDataSize = 0;
    void *pDataBuf = NULL;

    if (!ptMsg)
        return -ERRNO_EPARAMETER_INVALID;

    if (NULL == ptMsg->pData || 0 == ptMsg->nDataByteCnt)
        return ERRNO_SUCCESS;

    if (ptMsg && ptMsg->pData && ptMsg->nDataByteCnt > 0)
        free(ptMsg->pData);

    ptMsg->pData = NULL;

    ptMsg->nDataByteCnt = 0;

    return ERRNO_SUCCESS;
}


